package tech.yunland.shop.domain.service;

import com.moyuer.bsf.domain.model.HqlArgs;
import com.moyuer.bsf.domain.service.LogService;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import tech.yunland.shop.domain.dao.GoodsDao;
import tech.yunland.shop.domain.dao.PurchaseBillDao;
import tech.yunland.shop.domain.dao.PurchaseBillEntryDao;
import tech.yunland.shop.domain.dao.SNGenerator;
import tech.yunland.shop.domain.model.*;

import java.math.BigDecimal;
import java.util.*;

/**
 * 采购单服务类
 *
 * @author 文卡<wkwenka@gmail.com>  on 17-2-13.
 */
@Service
public class PurchaseBillService {

    @Autowired
    protected LogService logService;

    @Autowired
    private PurchaseBillDao purchaseBillDao;

    @Autowired
    private PurchaseBillEntryDao purchaseBillEntryDao;

    @Autowired
    private StoreBillService storeBillService;

    @Autowired
    private SNGenerator snGenerator;

    @Autowired
    private GoodsDao goodsDao;


    /**
     * 保存采购单据
     *
     * @param purchaseBill
     */
    public void savePurchase(PurchaseBill purchaseBill) {

//        String sn = snGenerator.gen("purchaseBill", purchaseBill.getOrganId());
//        purchaseBill.setSn(sn);
        purchaseBill.setBiz_type(Integer.valueOf(0));

        for (PurchaseBillEntry entry : purchaseBill.getEntries()) {
            String goodsId = entry.getGoods().getId();

            Goods goods = goodsDao.get(goodsId);

            if (goods == null) {
                throw new RuntimeException("选择商品异常：【您未选择商品或一次性选择多个商品】");
            }

            if (goods.getKindCode().intValue() != 10) {
                throw new RuntimeException(goods.getName() + "为非实物不能保存");
            }

            BigDecimal goodsPrice = goods.getPrice();

            //保存采购单
            purchaseBillDao.saveOrUpdate(purchaseBill);

            BigDecimal quantity = entry.getQuantity();

            if (quantity.intValue() <= 0) {
                throw new RuntimeException("商品数量应至少为1");
            }

            PurchaseBillEntry purchaseBillEntry = new PurchaseBillEntry();

            purchaseBillEntry.setGoods(goods);
            purchaseBillEntry.setQuantity(quantity);
            BigDecimal amount = goodsPrice.multiply(quantity);
            BigDecimal _amount = quantity.multiply(entry.getPurchasePrice());
            purchaseBillEntry.setAmount(_amount);
            purchaseBillEntry.setPrice(goodsPrice);
            purchaseBillEntry.setState(Integer.valueOf(1));
            purchaseBillEntry.setOwner(purchaseBill);
            purchaseBillEntry.setPurchasePrice(entry.getPurchasePrice());

            //保存购物单分录
            purchaseBillEntryDao.save(purchaseBillEntry);

        }

    }

    /**
     * 生成入库单
     *
     * @param purchaseBill
     */
    private StoreBill createStoreBill(PurchaseBill purchaseBill) {

        StoreBill storeBill = new StoreBill();
        storeBill.setSn(snGenerator.gen("sale", purchaseBill.getOrganId()));
        storeBill.setOrgan(purchaseBill.getOrgan());
        storeBill.setCreator(purchaseBill.getCreator());
        storeBill.setState(Integer.valueOf(0));
        storeBill.setDirection(Integer.valueOf(1));
        storeBill.setBiz_type(Integer.valueOf(2)); //采购入库
        storeBill.setBizBillId(purchaseBill.getId());
        storeBill.setBizBillSn(purchaseBill.getSn());
        storeBill.setRemark(purchaseBill.getRemark());
        storeBill.setHanderName(purchaseBill.getHanderName());


        HashSet<StoreBillEntry> storeBillEntries = new HashSet<>();
        Set<PurchaseBillEntry> entries = purchaseBill.getEntries();
        for (PurchaseBillEntry entry : entries) {

            if (entry.getState().intValue() != -1) { //过滤标记删除的分类
                StoreBillEntry storeBillEntry = new StoreBillEntry();
                storeBillEntry.setQuantity(entry.getQuantity());
                storeBillEntry.setGoods(entry.getGoods());
                storeBillEntry.setOwner(storeBill);
                storeBillEntry.setState(Integer.valueOf(1));
                storeBillEntries.add(storeBillEntry);
            }

        }
        storeBill.setPurchaseBill(purchaseBill);
        storeBill.setEntries(storeBillEntries);

        return storeBill;
    }

    /**
     * 欲采购 --> 已采购
     *
     * @param id
     */
    public void updatePurchaseBill(String id) {
        PurchaseBill purchaseBill = purchaseBillDao.get(id);
//        if (purchaseBill != null) {
//
//            if (purchaseBill.getBiz_type().intValue() != 1) {
//                purchaseBill.setBiz_type(Integer.valueOf(1));
//            } else {
//                throw new RuntimeException("此采购单已完成采购");
//            }
//
//        } else {
//            throw new RuntimeException("采购单不存在");
//        }

        if (purchaseBill != null) {
            if (purchaseBill.getState().intValue() == 0) {
                purchaseBill.setState(Integer.valueOf(1));
                purchaseBillDao.update(purchaseBill);
            }
        }

        // 采购单已采购自动生成入库单
        if (purchaseBill.getState().intValue() != 0) {
            StoreBill storeBill = createStoreBill(purchaseBill);
            storeBillService.saveStore(storeBill);
            logService.saveLog("采购单：[" + purchaseBill.getSn() + "] 完成采购，入库单：[" + storeBill.getSn() + "] 自动生成。", storeBill.getCreator());
        }
    }

    /**
     * 根据采购单据 id 删除 单据
     *
     * @param id
     */
    public void deletePurchaseBill(String id) {

        PurchaseBill purchaseBill = purchaseBillDao.get(id);


        if (purchaseBill != null && purchaseBill.getState().intValue() != -1) {

            if (purchaseBill.getState().intValue() == 1 || purchaseBill.getState().intValue() == 2) {
                throw new RuntimeException("该单据不能执行删除");
            }

            purchaseBill.setState(Integer.valueOf(-1));

            //删除该单据下的所有分录
            for (PurchaseBillEntry entry : purchaseBill.getEntries()) {
                if (entry.getState().intValue() == 1) {
                    deletePurchaseBillEntry(entry.getId());
                }
            }

        } else {
            throw new RuntimeException("该单据已经删除");
        }

        purchaseBillDao.update(purchaseBill);
        logService.saveLog("采购单：[" + purchaseBill.getSn() + "] 删除。", purchaseBill.getCreator());
    }


    /**
     * 根据主键获取采购单
     *
     * @param id
     * @return
     */
    public PurchaseBill getPurchaseBillById(String id) {
        return purchaseBillDao.get(id);
    }

    /**
     * 保存分录
     *
     * @param purchaseBillEntry
     */
    public void savePurchaseEntry(PurchaseBillEntry purchaseBillEntry) {
        String goodsId = purchaseBillEntry.getGoods().getId();
        BigDecimal quantity = purchaseBillEntry.getQuantity();
        String ownerId = purchaseBillEntry.getOwner().getId();

        if (quantity.intValue() <= 0) {
            throw new RuntimeException("商品数量应至少为1");
        }

        Goods goods = goodsDao.get(goodsId);

        if (goods == null) {
            throw new RuntimeException("选择商品异常：【您未选择商品或一次性选择多个商品】");
        }

        if (goods.getKindCode().intValue() != 10) {
            throw new RuntimeException(goods.getName() + "为非实物不能保存");
        }

        PurchaseBill purchaseBill = purchaseBillDao.get(ownerId);

        PurchaseBillEntry entry = new PurchaseBillEntry();
        entry.setGoods(goods);
        entry.setGoodsPrize(goods.getPrize());
        entry.setPrice(goods.getPrice());
        entry.setAmount(quantity.multiply(purchaseBillEntry.getPurchasePrice()));
        entry.setOwner(purchaseBill);
        entry.setState(purchaseBillEntry.getState());
        entry.setQuantity(quantity);
        entry.setPurchasePrice(purchaseBillEntry.getPurchasePrice());

        purchaseBillEntryDao.save(entry);


        if (purchaseBill != null && purchaseBill.getState().intValue() == 1) {
            throw new RuntimeException("该单据正在审批");
        }

        if (purchaseBill != null && purchaseBill.getState().intValue() == -2) { //如果该单据审批没有通过，修改过后状态改为暂存
            this.updateState(ownerId, 0);
        }
    }

    /**
     * 修改分录
     *
     * @param purchaseBillEntry
     */
    public void updatePurchaseEntry(PurchaseBillEntry purchaseBillEntry) {
        String goodsId = purchaseBillEntry.getGoods().getId();
        BigDecimal quantity = purchaseBillEntry.getQuantity();
        String entryid = purchaseBillEntry.getId();

        if (quantity.intValue() <= 0) {
            throw new RuntimeException("商品数量应至少为1");
        }

        Goods goods = goodsDao.get(goodsId);

        if (goods == null) {
            throw new RuntimeException("选择商品异常：【您未选择商品或一次性选择多个商品】");
        }

        if (goods.getKindCode().intValue() != 10) {
            throw new RuntimeException(goods.getName() + "为非实物不能保存");
        }

        PurchaseBillEntry entry = purchaseBillEntryDao.get(entryid);

        entry.setGoods(goods);
        entry.setGoodsPrize(goods.getPrize());
        entry.setPrice(goods.getPrice());
        entry.setQuantity(quantity);
        entry.setAmount(quantity.multiply(purchaseBillEntry.getPurchasePrice()));
        entry.setPurchasePrice(purchaseBillEntry.getPurchasePrice());

        purchaseBillEntryDao.saveOrUpdate(entry);

        PurchaseBill owner = entry.getOwner();

        if (owner != null && owner.getState().intValue() == 1) {
            throw new RuntimeException("该单据正在审批");
        }

        if (owner != null && owner.getState().intValue() == -2) { //如果该单据审批没有通过，修改过后状态改为暂存
            this.updateState(owner.getId(), 0);
        }
    }

    /**
     * 查询当前分录的详细信息
     *
     * @param id
     * @return
     */
    public PurchaseBillEntry getPurcahseBillEntryInfo(String id) {
        return purchaseBillEntryDao.get(id);
    }

    /**
     * 根据主键删除分录
     *
     * @param id 分录主键
     */
    public void deletePurchaseBillEntry(String id) {
        PurchaseBillEntry purchaseBillEntry = purchaseBillEntryDao.get(id);

        PurchaseBill purchaseBill = purchaseBillEntry.getOwner();

        if (purchaseBill != null && purchaseBill.getState().intValue() == 1) {
            throw new RuntimeException("该单据正在审批");
        }

        if (purchaseBill != null && purchaseBill.getState().intValue() == -2) { //如果该单据审批没有通过，修改过后状态改为暂存
            this.updateState(purchaseBill.getId(), 0);
        }

        if (purchaseBillEntry != null && purchaseBillEntry.getState().intValue() != -1) {
            purchaseBillEntry.setState(Integer.valueOf(-1));
        } else {
            throw new RuntimeException("该单已删除");
        }

        purchaseBillEntryDao.update(purchaseBillEntry);
    }

    //--------------------采购单据查询-----------------------

    /**
     * @param param   查询参数
     * @param biztype 采购类型  0：待采购    1：已采购
     * @param organId
     * @return
     */
    private HqlArgs getPurchaseHqlArgs(String param, Integer biztype, String organId, List<Integer> states) {

        param = StringUtils.trimToEmpty(param);

        Map<String, Object> args = new HashMap<>();

        String hql = "FROM PurchaseBill p WHERE p.entries.size>0 AND EXISTS (SELECT e.id FROM p.entries e WHERE e.state=1)";

        if (states != null && states.size() > 0) {
            if (states.size() == 1) {
                hql += " AND p.state = :state";
                args.put("state", states.get(0));
            } else {
                hql += " AND p.state IN :states";
                args.put("states", states);
            }
        } else {
            hql += " AND p.state <> -1";
        }

        if (StringUtils.isNotBlank(StringUtils.trimToEmpty(organId))) {
            hql += " AND p.organ.id = :organId";
            args.put("organId", organId);
        }

        if (biztype != null) {
            hql += " AND p.biz_type = :biz_type";
            args.put("biz_type", biztype);
        }

        if (StringUtils.isNotBlank(param)) {
            hql += " AND (p.sn LIKE :param OR p.remark LIKE :param OR (CASE biz_type WHEN '0' THEN '待采购' WHEN '1' THEN '已采购' END) LIKE :param OR";
//            hql += " (CASE p.state WHEN '0' THEN '暂存' WHEN '-2' THEN '未通过' WHEN '1' THEN '审批中' WHEN '2' THEN '通过' END) LIKE :param OR";
            hql += " p.creator.name LIKE :param OR";
            hql += " EXISTS (SELECT e.id FROM p.entries e WHERE e.state=1 AND (e.goods.name LIKE :param OR e.goods.spell LIKE :param)))";
            args.put("param", "%" + param + "%");
        }


        return new HqlArgs(hql, args);
    }

    /**
     * 获取所有采购单据
     *
     * @param param
     * @param organId
     * @param biztype
     * @param page
     * @param rows
     * @return
     */
    public List<PurchaseBill> getAllBill(String param, String organId, Integer biztype, List<Integer> states,
                                         Integer page, Integer rows) {
        HqlArgs purchaseHqlArgs = getPurchaseHqlArgs(param, biztype, organId, states);
        String s = purchaseHqlArgs.getHql() + " ORDER BY p.bizdate DESC";
        List<PurchaseBill> purchaseBills = purchaseBillDao.findByNamedParam(s, page, rows, purchaseHqlArgs.getArgs());
        return purchaseBills;
    }

    /**
     * 获取采购单据数量
     *
     * @param param
     * @param organId
     * @param biztype
     * @return
     */
    public Integer getAllBillSize(String param, String organId, Integer biztype, List<Integer> states) {
        HqlArgs purchaseHqlArgs = getPurchaseHqlArgs(param, biztype, organId, states);
        return (int) purchaseBillDao.getCount(purchaseHqlArgs.getHql(), purchaseHqlArgs.getArgs());
    }

    //----------------------采购单下分录查询------------------

    /**
     * 根据采购单 id 获取其下的所有分录
     *
     * @param ownerId
     * @param page
     * @param rows
     * @return
     */
    public List<PurchaseBillEntry> getBillEntry(String ownerId, Integer page, Integer rows) {

        String hql = "FROM PurchaseBillEntry e WHERE e.state=1 AND e.owner.id = ? ORDER BY e.createTime DESC";

        List<PurchaseBillEntry> purchaseBillEntries = purchaseBillEntryDao.find(hql, page, rows, ownerId);

        return purchaseBillEntries;
    }

    /**
     * 获取采购单 id 获取其下的分录数量
     *
     * @param ownerId
     * @return
     */
    public Integer getBillEntrySize(String ownerId) {
        String hql = "FROM PurchaseBillEntry e WHERE e.state=1 AND e.owner.id = ? ORDER BY e.createTime DESC";
        return purchaseBillEntryDao.find(hql, ownerId).size();
    }

    /**
     * 更改状态
     *
     * @param id
     * @param state
     */
    public void updateState(String id, Integer state) {
        PurchaseBill purchaseBill = purchaseBillDao.get(id);
        purchaseBill.setState(state);
        purchaseBillDao.update(purchaseBill);
    }

    /**
     * 修改单据备注
     *
     * @param id
     * @param remark
     */
    public void updateRemark(String id, String remark) {
        PurchaseBill purchaseBill = purchaseBillDao.get(id);
        if (purchaseBill != null) {
            purchaseBill.setRemark(remark);
            purchaseBillDao.update(purchaseBill);
        }
    }

    /***
     * 修改单据
     * @param bill
     */
    public void updateBill(PurchaseBill bill) {
        String sql = "UPDATE purchase_bill SET remark=?,kind_code=?,handername=? WHERE id = ?";
        Session session = this.purchaseBillDao.getSession();
        SQLQuery sqlQuery = session.createSQLQuery(sql);
        sqlQuery.setString(0, bill.getRemark());
        sqlQuery.setInteger(1, bill.getKindCode());
        sqlQuery.setString(2, bill.getHanderName());
        sqlQuery.setString(3, bill.getId());
        sqlQuery.executeUpdate();
    }
}
